//input stream, extremly fast but not stl-compliant (yet?)
//$Id: fast_stream.h 395 2010-03-26 14:01:03Z Oleg.Bulychov $
#pragma once

#include <string>
#include <iostream>
#include <fstream>
//__________________________________________________________________________________
//__________________________________________________________________________________
class fast_istream
{
protected:
    char const* text_;
    size_t      pos_;
    size_t      len_;
public:
    explicit fast_istream(char const* str = NULL, size_t cch = 0): text_(str), pos_(0),
        len_(cch)
    {}

    fast_istream& operator >> (std::string& s)
    {
        for (;pos_ < len_; ++pos_)
        {
            char c = text_[pos_];
            if (c > ' ')
            {
                size_t from = pos_;
                for (++pos_; pos_ < len_; ++pos_)
                {
                    c = text_[pos_];
                    if (c <= ' ')
                        break;
                }
                s.assign(&text_[from], pos_ - from);
                return *this;
            }
        }
        s.clear();
        return *this;
    }

    fast_istream& operator >> (int& i)
    {
        read_Signed(i);
        return *this;
    }

    fast_istream& operator >> (unsigned int& u)
    {
        read_Unsigned(u);
        return *this;
    }

    fast_istream& operator >> (long& i)
    {
        read_Signed(i);
        return *this;
    }

    fast_istream& operator >> (unsigned long& u)
    {
        read_Unsigned(u);
        return *this;
    }

#if (!INT64_EQUAL_LONG)
    fast_istream& operator >> (int64_t& i)
    {
        read_Signed(i);
        return *this;
    }

    fast_istream& operator >> (uint64_t& u)
    {
        read_Unsigned(u);
        return *this;
    }
#endif

    fast_istream& operator >> (double& d)
    {
        d = read_Double();
        return *this;
    }

    fast_istream& operator >> (float& f)
    {
        f = (float)read_Double();
        return *this;
    }

protected:
    template<typename T>
    void read_Digits(T& number)
    {
        for (; pos_ < len_; ++pos_)
        {
            char c = text_[pos_];
            if ('0' <= c && c <= '9')
            {
                int digval = c - '0';
                number = number * 10 + digval;
            }
            else
                break;
        }
    }

    template<typename T>
    void read_Signed(T& number)
    {
        number = 0;
        for (;pos_ < len_; ++pos_)
        {
            char c = text_[pos_];
            if (c > ' ')
            {
                bool negative = '-' == c;
                if (negative)
                    ++pos_;

                read_Digits(number);
                if (negative)
                    number = -number;
                return;
            }
        }
    }

    template<typename T>
    void read_Unsigned(T& number)
    {
        number = 0;
        for (;pos_ < len_; ++pos_)
        {
            char c = text_[pos_];
            if (c > ' ')
            {
                read_Digits(number);
                return;
            }
        }
    }

    double read_Double()
    {
        char const* begin_ptr = &text_[pos_];
        char* end_ptr;
        double d = strtod(begin_ptr, &end_ptr);//:can read over end of buffer
        //:make sure buffer is null-terminated

        pos_ += int(end_ptr - begin_ptr);
        return d;
    }
};
//__________________________________________________________________________________
class fast_istream2:
    public fast_istream
{
    std::vector<char> buffer_;
public:
    fast_istream2()
    {}

    bool open(char const* szFile)
    {
        std::ifstream in(szFile);
        if (!in)
        {
            std::cout << "ERROR: '" << szFile << "' not found" << std::endl;
            return 0;
        }
        in.seekg(0, std::ios::end);
        std::streamsize length = in.tellg();
        in.seekg(0, std::ios::beg);
        buffer_.resize(length + 1);
        if (length <= 0)
        {
            std::cout << "ERROR: '" << szFile << "' is empty" << std::endl;
            return 0;
        }
        in.read(&buffer_[0], length);
        text_ = &buffer_[0];
        len_ = length;
        return true;
    }
};


//EOF!
